package com.ruoyi.training.controller;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.deepoove.poi.XWPFTemplate;
import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.training.dto.ApplicationFormData;
import com.ruoyi.training.dto.TrainingProgress;
import com.ruoyi.training.dto.registration.RegistrationDto;
import com.ruoyi.training.dto.registration.RegistrationImport;
import com.ruoyi.training.vo.registration.RegistrationExportVo;
import com.ruoyi.training.vo.registration.RegistrationGroupVo;
import com.ruoyi.training.vo.registration.RegistrationSubmitVo;
import com.ruoyi.training.vo.registration.RegistrationVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.training.domain.Registration;
import com.ruoyi.training.service.IRegistrationService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;

/**
 * 报名Controller
 *
 * @author hcc
 * @date 2025-09-17
 */
@RestController
@RequestMapping("/registration")
public class RegistrationController extends BaseController {
    @Autowired
    private IRegistrationService registrationService;

    @Autowired
    private TokenService tokenService;

    /**
     * 查询报名列表
     */
    @RequiresPermissions("training:registration:list")
    @GetMapping("/list")
    public TableDataInfo list(Registration registration) {
        startPage();
        List<Registration> list = registrationService.selectRegistrationList(registration);
        return getDataTable(list);
    }

    /**
     * 查询报名列表
     */
    @RequiresPermissions("training:registration:list")
    @GetMapping("/registrationList")
    public TableDataInfo list(RegistrationVo registrationVo) {
        startPage();
        List<RegistrationDto> list = registrationService.selectList(registrationVo);
        return getDataTable(list);
    }

    /**
     * 查询培训进度
     * lqx
     */
    @GetMapping("/trainingProgress/{studentId}")
    public TableDataInfo listTrainingProgress(@PathVariable("studentId")String studentId) {
        startPage();
        List<TrainingProgress> list = registrationService.selectListTrainingProgress(studentId);
        return getDataTable(list);
    }

    /**
     * 查询培训进度-后端获取id
     * lqx
     */
    @GetMapping("/trainingProgres")
    public TableDataInfo listTrainingProgress() {
        String studentId = SecurityUtils.getLoginUser().getSysUser().getStudentId();
        startPage();
        if (!"".equals(studentId) && studentId != null){
            List<TrainingProgress> list = registrationService.selectListTrainingProgress(studentId);
            return getDataTable(list);
        }else{
            return null;
        }
    }

    @Log(title = "报名信息导入", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<RegistrationImport> util = new ExcelUtil<RegistrationImport>(RegistrationImport.class);
        List<RegistrationImport> registrationImportList = util.importExcel(file.getInputStream());
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        String operName = loginUser.getUsername();
        String message = registrationService.importRegistration(registrationImportList, updateSupport, operName);
        return AjaxResult.success(message);
    }

    /**
     * 导出报名列表
     */
    @RequiresPermissions("training:registration:export")
    @Log(title = "报名", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Registration registration) {
        List<Registration> list = registrationService.selectRegistrationList(registration);
        ExcelUtil<Registration> util = new ExcelUtil<Registration>(Registration.class);
        util.exportExcel(response, list, "报名数据");
    }

    /**
     * 导出申请表
     */
    @RequiresPermissions("training:registration:export")
    @Log(title = "申请表", businessType = BusinessType.EXPORT)
    @PostMapping("/export/applicationForm")
    public void export(HttpServletResponse response, @RequestBody RegistrationExportVo registrationExportVo) throws Exception {
        String[] registrationIds = registrationExportVo.getRegistrationIds();

        // 1. 校验选中ID
        if (StringUtils.isEmpty(registrationIds)) {
            throw new IllegalArgumentException("请选择需要导出的数据");
        }

        // 2. 读取模板并缓存到字节数组
        String templatePath = "/templates/特种设备作业人员资格申请表.docx";
        byte[] templateBytes;
        try (InputStream templateStream = getClass().getResourceAsStream(templatePath)) {
            if (templateStream == null) {
                throw new FileNotFoundException("模板文件不存在：" + templatePath);
            }
            // 将模板流读取到字节数组，缓存起来
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = templateStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            templateBytes = baos.toByteArray();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("导出失败：模板文件未找到（需为Office生成的.docx）");
        }

        // 3. 查询数据
        List<ApplicationFormData> dataList = registrationService.selectRegistrationByIds(registrationIds);
        if (dataList.isEmpty()) {
            throw new RuntimeException("未查询到对应数据");
        }

        // 4. 区分单文件和多文件处理
        try {
            if (dataList.size() == 1) {
                // 单个文件：用缓存创建新流
                try (InputStream singleStream = new ByteArrayInputStream(templateBytes)) {
                    exportSingleWord(response, singleStream, dataList.get(0));
                }
            } else {
                // 多个文件：传入缓存的字节数组，内部为每个文件创建新流
                exportZip(response, templateBytes, dataList);
            }
        } catch (Exception e) {
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    /**
     * 单个文件导出：直接输出带勾选框的Word
     */
    private void exportSingleWord(HttpServletResponse response, InputStream templateStream, ApplicationFormData data) throws Exception {
        // 处理文件名null值，避免非法文件名
        String fileNamePrefix = "特种设备培训申请_" + (data.getStudentName() == null ? "未知用户" : data.getStudentName());
        try (
                BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
                // 自动关闭template，无需手动close
                XWPFTemplate template = XWPFTemplate.compile(templateStream).render(buildDataModel(data))
        ) {
            // 响应配置
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            String fileName = URLEncoder.encode(fileNamePrefix, StandardCharsets.UTF_8.name()) + ".docx";
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + fileName);
            response.setHeader("Pragma", "no-cache");

            // 写入响应
            template.write(bos);
            bos.flush();
        }
    }

    /**
     * 多个文件导出：打包为ZIP（核心修正）
     */
    private void exportZip(HttpServletResponse response, byte[] templateBytes, List<ApplicationFormData> dataList) throws Exception {
        try (
                ByteArrayOutputStream zipBaos = new ByteArrayOutputStream();
                ZipOutputStream zipOut = new ZipOutputStream(zipBaos);
                BufferedOutputStream responseBos = new BufferedOutputStream(response.getOutputStream())
        ) {
            for (ApplicationFormData data : dataList) {
                // 处理文件名null值，避免非法字符
                String studentName = data.getStudentName() == null ? "未知用户" : data.getStudentName();
                String idNumber = data.getIdNumber() == null ? "" : "_" + data.getIdNumber();
                String zipEntryName = "特种设备培训申请_" + studentName + idNumber + ".docx";

                // 为每个文件创建独立的模板输入流（关键修正）
                try (
                        InputStream fileStream = new ByteArrayInputStream(templateBytes);
                        ByteArrayOutputStream wordBaos = new ByteArrayOutputStream();
                        XWPFTemplate template = XWPFTemplate.compile(fileStream).render(buildDataModel(data))
                ) {
                    // 渲染Word到字节流
                    template.write(wordBaos);

                    // 添加到ZIP包
                    ZipEntry zipEntry = new ZipEntry(zipEntryName);
                    zipOut.putNextEntry(zipEntry);
                    zipOut.write(wordBaos.toByteArray());
                    zipOut.closeEntry();
                }
            }

            // ZIP打包完成，响应给前端
            zipOut.finish();
            response.setContentType("application/zip");
            String zipFileName = URLEncoder.encode("特种设备培训申请批量导出", StandardCharsets.UTF_8.name()) + "_" + System.currentTimeMillis() + ".zip";
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + zipFileName);

            responseBos.write(zipBaos.toByteArray());
            responseBos.flush();
        }
    }


    /**
     * 构建数据模型（核心：处理勾选框状态）
     */
    private Map<String, Object> buildDataModel(ApplicationFormData data) {
        Map<String, Object> model = new HashMap<>();
        // 基础字段
        model.put("studentName", data.getStudentName());
        model.put("idNumber", data.getIdNumber());
        model.put("phonenumber", data.getPhonenumber());
        model.put("address", data.getAddress());
        model.put("sex", data.getSex());
        model.put("birthDate", data.getBirthDate());
        model.put("qualification", data.getQualification());
        model.put("nation", data.getNation());
        model.put("unitName", data.getUnitName());
        model.put("unitAddress", data.getUnitAddress());
        model.put("postCode", data.getPostCode());
        model.put("url", data.getUrl());

        // 勾选框处理：根据业务逻辑动态设置勾选状态
        // 是否提交身份证明材料
        model.put("hasIdNumber", data.getHasIdNumber() ? "☑" : "□");
        model.put("hasQualification", data.getHasQualification() ? "☑" : "□");
        model.put("hasCheckup", data.getHasCheckup() ? "☑" : "□");
        return model;
    }

    /**
     * 获取报名详细信息
     */
    @RequiresPermissions("training:registration:query")
    @GetMapping(value = "/{registrationId}")
    public AjaxResult getInfo(@PathVariable("registrationId") String registrationId) {
        return success(registrationService.selectRegistrationByRegistrationId(registrationId));
    }

    /**
     * 新增报名
     */
    @RequiresPermissions("training:registration:add")
    @Log(title = "报名", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody Registration registration) {
        return toAjax(registrationService.insertRegistration(registration));
    }

    /**
     * 新增报名
     */
    @RequiresPermissions("training:registration:add")
    @Log(title = "报名", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    public AjaxResult addRegistration(@RequestBody RegistrationSubmitVo registrationSubmitVo) {
        if (StringUtils.isEmpty(registrationSubmitVo.getProjectId())) {
            return error("请选择要报名的项目");
        }
        return toAjax(registrationService.addRegistration(registrationSubmitVo));
    }

    /**
     * 新增集体报名
     */
    @RequiresPermissions("training:registration:add")
    @Log(title = "报名", businessType = BusinessType.INSERT)
    @PostMapping("/addGroup")
    public AjaxResult addRegistrationGroup(@RequestBody RegistrationGroupVo registrationGroupVo) {
        return toAjax(registrationService.addRegistrationGroup(registrationGroupVo));
    }

    /**
     * 修改报名
     */
    @RequiresPermissions("training:registration:edit")
    @Log(title = "报名", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody Registration registration) {
        return toAjax(registrationService.updateRegistration(registration));
    }

    /**
     * 修改报名
     */
    @RequiresPermissions("training:registration:edit")
    @Log(title = "报名", businessType = BusinessType.UPDATE)
    @PutMapping("/update")
    public AjaxResult editRegistration(@RequestBody RegistrationSubmitVo registrationSubmitVo) {
        return toAjax(registrationService.update(registrationSubmitVo));
    }

    /**
     * 删除报名
     */
    @RequiresPermissions("training:registration:remove")
    @Log(title = "报名", businessType = BusinessType.DELETE)
    @DeleteMapping("/{registrationIds}")
    public AjaxResult remove(@PathVariable String[] registrationIds) {
        return toAjax(registrationService.deleteRegistrationByRegistrationIds(registrationIds));
    }

    /**
     * 逻辑删除报名
     */
    @RequiresPermissions("training:registration:remove")
    @Log(title = "报名", businessType = BusinessType.DELETE)
    @DeleteMapping("/removeRegistration/{registrationIds}")
    public AjaxResult removeRegistration(@PathVariable String[] registrationIds) {
        return toAjax(registrationService.removeRegistrationByRegistrationIds(registrationIds));
    }

    /**
     * 查询个人报名列表
     */
    @RequiresPermissions("training:registration:list")
    @GetMapping("/personRegistrationList")
    public TableDataInfo personRegistrationList(RegistrationVo registrationVo) {
        startPage();
        List<RegistrationDto> list = registrationService.personRegistrationList(registrationVo);
        return getDataTable(list);
    }
}
